package com.foreveross.crawl.adapter.sub.impl20140402.v3;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.net.URI;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import com.foreveross.crawl.adapter.AbstractAdapter;
import com.foreveross.crawl.adapter.PlaneInfoEntityBuilder;
import com.foreveross.crawl.common.util.RegHtmlUtil;
import com.foreveross.crawl.domain.airfreight.AbstractPlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.CabinEntity;
import com.foreveross.crawl.domain.airfreight.StopOverEntity;
import com.foreveross.crawl.domain.airfreight.TransitEntity;
import com.foreveross.crawl.domain.airfreight.doub.CabinRelationEntity;
import com.foreveross.crawl.domain.airfreight.doub.DoublePlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnCabinEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnDoublePlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnStopOverEntity;
import com.foreveross.crawl.domain.airfreight.doub.ReturnTransitEntity;
import com.foreveross.crawl.domain.airfreight.single.SinglePlaneInfoEntity;
import com.foreveross.taskservice.common.bean.TaskModel;
import com.ibm.db2.jcc.am.lo;

/**
 * 美国联合航空
 * @author stb
 *
 */
public class UnitedAdapter extends AbstractAdapter {
	
	private static final String HOMEURL = "http://www.united.com/web/zh-CN/default.aspx";
	private static final String SEARCHOWURL = "http://www.united.com/web/zh-CN/apps/booking/flight/searchOW.aspx?HP=1";
	private static final String SEARCHRTURL = "http://www.united.com/web/zh-CN/apps/booking/flight/searchRT.aspx?HP=1";
	private static final String SEARCHURL = "http://www.united.com/web/zh-CN/apps/booking/flight/searchResult1.aspx";
	private static final String SEARCH2URL = "http://www.united.com/web/zh-CN/apps/booking/flight/searchResult2.aspx";
	
	
	private static final String carrierKey = "UA";
	private static final String carrierName = "美联航";
	private static final String carrierFullName = "美国联合航空";
	
	//查询返程，如果都失败则认为任务失败
	private static final int queryRoundTimes = 3;

	//单程查询税费页次数
	private static final int queryOneWayTaxTimes = 3;
	
	//查询税费页次数 不查询税费页则设为0 列表显示的是合计价，包含税费的(查询返程税费任务会很慢)
	private static final int queryRoundTaxTimes = 0;//想要税费，还原到开始状态 3
	
	private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
	
	/**
	 * 中转的航班如果是美联航，就返回，否则返回空
	 * @param carriKey
	 * @return
	 */
	private static String getCarriName(String carriKey){
		if(UnitedAdapter.carrierKey.equals(carriKey)){
			return carrierName;
		}
		return null;
	}
	
	/**
	 * 中转的航班如果是美联航，就返回，否则返回空
	 * @param carriKey
	 * @return
	 */
	private static String getCarriFullName(String carriKey){
		if(UnitedAdapter.carrierKey.equals(carriKey)){
			return carrierFullName;
		}
		return null;
	}
	
	public UnitedAdapter(TaskModel taskQueue) {
		super(taskQueue);
	}

	@Override
	public List<Object> paraseToVo(Object fetchObject) throws Exception {
		if(fetchObject == null){
			return null;
		}
		return (List<Object>)fetchObject;
	}

	@Override
	public String getUrl() throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object fetch(String url) throws Exception {
		switch (super.getRouteType()) {
		case INTERNATIONAL_ONEWAY:
			return fetch();
		case INTERNATIONAL_ROUND:
			return fetch();
		}
		return null;
	}
	
	/**
	 * 抓取国际单程
	 * @return
	 * @throws Exception
	 */
	private Object fetchInterOneway() throws Exception{
		return null;
	}
	
	
	/**
	 * 获取查询条件
	 * @param form
	 * @return
	 */
	private Map<String,String> getSearchParams(Element form){
		Map<String,String> map = new LinkedHashMap<String, String>();
		for(Element name : form.select("[name]")){
			map.put(name.attr("name"), name.val());
		}
		//map.put("ctl00$ContentInfo$Booking1$Cabins$cboCabin", "Coach");//舱位
		map.put("ctl00$ContentInfo$Booking1$SearchType", taskQueue.getIsReturn() == 1 ?"rdoSearchType1" : "rdoSearchType2");//往返，单程是rdoSearchType2
		map.put("ctl00$ContentInfo$Booking1$Origin$txtOrigin", taskQueue.getFromCity());//出发城市
		map.put("ctl00$ContentInfo$Booking1$Destination$txtDestination", taskQueue.getToCity());//到达城市
		map.put("ctl00$ContentInfo$Booking1$DepDateTime$Depdate$txtDptDate",getFormatDate(taskQueue.getFlightDate())); //去程日期
		map.put("ctl00$ContentInfo$Booking1$RetDateTime$Retdate$txtRetDate", getFormatDate(taskQueue.getReturnGrabDate())); //回程日期
		
		map.put("ctl00$ContentInfo$Booking1$Adult$cboAdult", "1");//成人数
		map.put("ctl00$ContentInfo$Booking1$SearchBy$SearchBy", "rdosearchby1");//搜索条件  价格
		map.put("ctl00$ContentInfo$manageres$confirmationOptions", "rdoFlight");
		map.put("ctl00$ContentInfo$Booking1$DepDateTime$DateFlex", "rdoDateSpecific");//搜索具体日期
		
		map.remove("ctl00$ContentInfo$accountsummary$rememberme$chkRemMe");
		map.remove("ctl00$ContentInfo$manageres$btnImport");
		map.remove("rd2Name");
		map.remove("ctl00$ContentInfo$Checkinflightstatus$btnFlightStatus");
		map.remove("ctl00$ContentInfo$Booking1$Nearbyair$chkFltOpt");
		map.remove("ctl00$ContentInfo$Booking1$Direct$chkFltOpt");
		map.remove("ctl00$CustomerHeader$ChangeBtn");
		map.remove("ddlCountries");
		map.remove("rd3Name");
		map.remove("ctl00$ContentInfo$accountsummary$btnOnePassSignIn");
		map.remove("__EVENTARGUMENT");
		map.remove("ctl00$CustomerHeader$btnSearch");
		map.remove("ctl00$ContentInfo$Booking1$AltDate$chkFltOpt");
		map.remove("ctl00$ContentInfo$Checkinflightstatus$btnCheckIn");
		map.remove("resultLang");
		map.remove("rd1Name");
		map.remove("aspnetForm");
		
		return map;
	}
	
	/**
	 *抓取国际往返
	 * @return
	 * @throws Exception
	 */
	private Object fetch() throws Exception{
		logger.info("抓取开始-------------------");
		HttpGet g = null;
		HttpPost p = null;
		HttpClient h = getHttpClient();
		String page = null;
		Document doc = null;
		
		//各段航班号-实体
		Map<String,AbstractPlaneInfoEntity> map = new HashMap<String, AbstractPlaneInfoEntity>();
		
		g = new HttpGet(HOMEURL);
		page = excuteRequest(h, g, true);
	    doc = Jsoup.parse(page);
		Map<String,String> params = getSearchParams(doc.getElementById("aspnetForm"));
		Elements options = doc.getElementById("ctl00_ContentInfo_Booking1_Cabins_cboCabin").select("option");
		//舱位
		logger.info("循环舱位开始---------------------");
		for(Element e : options){
			if(!e.html().contains("经济")){//只取经济舱(过滤)
				break;
			}
			try{
				params.put("ctl00$ContentInfo$Booking1$Cabins$cboCabin", e.val());
				p = getBasePost(HOMEURL,params) ;
				p.setHeader("Referer",HOMEURL);
				excuteRequest(h, p, false);
			    g = new HttpGet(taskQueue.getIsReturn() == 1 ? SEARCHRTURL : SEARCHOWURL);
				page = excuteRequest(h, g, true);
				doc = Jsoup.parse(page);
				
			}catch(Exception ex){
				//如果经济舱的数据抓不到则抛出异常
				if(e.val().equals("Coach")){
					throw ex;
				}else{
					logger.info("抓取舱位:" + e.text() + "失败");
					continue;
				}
			}
			
			//航班信息
			Elements trs = doc.getElementById("revenueSegments").select("tr[id$=trSegBlock]");
			parase(map, trs, e);
		}
		
		/*BufferedWriter writer = new BufferedWriter(new FileWriter(new File("C:/Users/like/Desktop/test.txt")));
		writer.write(page);
		writer.close();*/
		
		/*g = new HttpGet(SEARCHURL);
		res = h.execute(g);
	    page = EntityUtils.toString(res.getEntity());
	    writer = new BufferedWriter(new FileWriter(new File("C:/Users/like/Desktop/test1.txt")));
	    writer.write(page);
	    writer.close();*/
		logger.info("排序价格-------------------------");
		List<AbstractPlaneInfoEntity> list = mapToList(map);
		PlaneInfoEntityBuilder.buildLimitPrice(list);
		return  Arrays.asList(list.toArray());
	}
	
	/**
	 * 把map的值取出来放到list
	 * @param map
	 * @return
	 */
	private static List<AbstractPlaneInfoEntity> mapToList(Map<String,AbstractPlaneInfoEntity> map){
		List<AbstractPlaneInfoEntity> list = new ArrayList<AbstractPlaneInfoEntity>();
		for(String key : map.keySet()){
			list.add(map.get(key));
		}
		return list;
	}
	
	private void parase(Map<String,AbstractPlaneInfoEntity> map,Elements trs,Element cabinElement) throws Exception{
		logger.info("解析开始----------------------");
		if(taskQueue.getIsReturn() == 1){
			paraseRT(map, trs, cabinElement);
		}else{
			paraseOW(map, trs, cabinElement);
		}
	}
	
	/**
	 * 组织单程
	 * @param map
	 * @param trs
	 * @param cabinElement
	 * @throws Exception
	 */
	private void paraseOW(Map<String,AbstractPlaneInfoEntity> map,Elements trs,Element cabinElement) throws Exception{
		SinglePlaneInfoEntity entity = null;
		for(Element tr : trs){
			//每一个航班里面有若干个tr  单数tr是航班，双数是中转信息
			Elements allTrs = tr.select("td.tdSegmentBlock table tbody>tr");
			Elements subTrs = getSubTranTrs(allTrs);
			String flightNos = "";
			Elements flighttds = tr.select("td.tdSegmentDtl");
			//用各段的航班号拼装起来，唯一确定一条航线
			for(Element flighttd : flighttds){ 
				String flightNo= flighttd.select("div").first().select("b").text();
				flightNos += flightNo;
			}
			
			//已经添加过的，不用再添加航班和中转信息
			if(map.containsKey(flightNos)){
				entity = (SinglePlaneInfoEntity)map.get(flightNos);
			}else{
				Element trfirst= subTrs.first();
				Element trlast = subTrs.last();
				entity = (SinglePlaneInfoEntity)PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, carrierKey, carrierName, carrierFullName,getStartTime(trfirst) , getEndTime(trlast),
					getFlightNo(trfirst), null, null, null, getFlightType(trfirst));
				entity.setFlightDuration(getStayTime(getFlightDuration(trlast)));
				if(subTrs.size() > 1){
					for(int i = 0;i < subTrs.size(); i = i + 2){
						String no = getFlightNo(subTrs.get(i));
						String key = no.substring(0,2);
						TransitEntity trans = PlaneInfoEntityBuilder.buildTransitEntity(no, no,
								key, getCarriName(key), getCarriFullName(key), getFromAirPort(subTrs.get(i)), getFromAirPortName(subTrs.get(i)),
								getToAirPort(subTrs.get(i)), getToAirPortName(subTrs.get(i)), getFlightType(subTrs.get(i)));
						//这个字段记不了，因为有多种舱位类型，而一个航班的中转是唯一的
						//trans.setCabinName();
 						trans.setStartTime(getFormat(getStartTime(subTrs.get(i))));
						trans.setEndTime(getFormat(getEndTime(subTrs.get(i))));
						//中转的停留时间记在前一中转中
						if(i < subTrs.size() - 1){
							trans.setStayTime(getStopStayTime(subTrs.get(i + 1)));
						}
						entity.getTransits().add(trans);
					}
				}
				map.put(flightNos, entity);
			}
			addStopOver(entity, getSubStopTrs(allTrs));
			
			
			String cabinName = getCabinName(subTrs.get(0));
			String priceText = tr.select("td.tdPrice").select("span.fResultsPrice").first().text().replaceAll(",", "");
			String currency = priceText.replaceAll("[\\d]", "");
			currency = currency.replaceAll("\\$", "USD").replaceAll("￥", "CNY").replaceAll("[^A-Z]", "");
			if(!currency.equals("CNY") && !currency.equals("USD")){
				logger.info("价格符号：" + currency + "请查看");
				throw new Exception("价格符号错误");
			}
			entity.setCurrency(currency);
			CabinEntity cabin = PlaneInfoEntityBuilder.buildCabinInfo(cabinElement.text(),RegHtmlUtil.regStr(cabinName, "\\((\\w{1})\\)") ,cabinName, 
					null, null, priceText.replaceAll("[^\\d\\.]", ""), null, null, CabinEntity.class);
			
			for(int i = 0;i < queryOneWayTaxTimes;i++){
				logger.info("单程抓取税费-------------");
				try{
					String page = fetchPrice(getPriceUrl(subTrs.first()));
					Document dc = Jsoup.parse(page);
					cabin.setPrice(getDouble(dc.getElementById("ctl00_ContentInfo_priceRevenueSummary_Price_ctl00_tdDisplayValue").text()));
					cabin.setTaxesPrice(getDouble(dc.getElementById("ctl00_ContentInfo_priceRevenueSummary_Price_ctl01_tdDisplayValue").text()));
					cabin.setOriginalPrice(getDouble(dc.getElementById("ctl00_ContentInfo_priceRevenueSummary_Price_ctl02_tdDisplayValue").text()));
					break;
				}catch(Exception e){
					logger.info("单程第" + (i + 1) + "次请求裸价和税费失败", e);
					switchProxyipByHttClient();
				}
			}
			entity.getCabins().add(cabin);
		}
	}
	
	/**
	 * 组织往返
	 * @param map
	 * @param trs
	 * @param cabinElement
	 * @throws Exception
	 */
	private void paraseRT(Map<String,AbstractPlaneInfoEntity> map,Elements trs,Element cabinElement) throws Exception{
		DoublePlaneInfoEntity entity = null;
		for(Element tr : trs){
			//每一个航班里面有若干个tr  单数tr是航班，双数是中转信息
			Elements allTrs = tr.select("td.tdSegmentBlock table tbody>tr");
			Elements subTrs = getSubTranTrs(allTrs);
			String flightNos = "";
			Elements flighttds = tr.select("td.tdSegmentDtl");
			//用各段的航班号拼装起来，唯一确定一条航线
			for(Element flighttd : flighttds){ 
				String flightNo= flighttd.select("div").first().select("b").text();
				flightNos += flightNo;
			}
			
			//已经添加过的，不用再添加航班和中转信息
			if(map.containsKey(flightNos)){
				entity = (DoublePlaneInfoEntity)map.get(flightNos);
			}else{
				Element trfirst= subTrs.first();
				Element trlast = subTrs.last();
				entity = (DoublePlaneInfoEntity)PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, carrierKey, carrierName, carrierFullName,getStartTime(trfirst) , getEndTime(trlast),
					getFlightNo(trfirst), null, null, null, getFlightType(trfirst));
				entity.setFlightDuration(getStayTime(getFlightDuration(trlast)));
				if(subTrs.size() > 1){
					for(int i = 0;i < subTrs.size(); i = i + 2){
						String no = getFlightNo(subTrs.get(i));
						String key = no.substring(0,2);
						TransitEntity trans = PlaneInfoEntityBuilder.buildTransitEntity(no, no,
								key, getCarriName(key), getCarriFullName(key), getFromAirPort(subTrs.get(i)), getFromAirPortName(subTrs.get(i)),
								getToAirPort(subTrs.get(i)), getToAirPortName(subTrs.get(i)), getFlightType(subTrs.get(i)));
						//这个字段记不了，因为有多种舱位类型，而一个航班的中转是唯一的
						//trans.setCabinName();
 						trans.setStartTime(getFormat(getStartTime(subTrs.get(i))));
						trans.setEndTime(getFormat(getEndTime(subTrs.get(i))));
						//中转的停留时间记在前一中转中
						if(i < subTrs.size() - 1){
							trans.setStayTime(getStopStayTime(subTrs.get(i + 1)));
						}
						entity.getTransits().add(trans);
					}
				}
				map.put(flightNos, entity);
			}
			
			addStopOver(entity, getSubStopTrs(allTrs));
			String cabinName = getCabinName(subTrs.get(0));
			CabinEntity cabin = PlaneInfoEntityBuilder.buildCabinInfo(cabinElement.text(),RegHtmlUtil.regStr(cabinName, "\\((\\w{1})\\)") ,cabinName, 
					null, null, null, null, null, CabinEntity.class);
			entity.getCabins().add(cabin);
			
			String roundObject = null;
			for(int i = 0;i < queryRoundTimes; i++){
				logger.info("请求返程-------------");
				try{
					roundObject = fetchRound(getRoundUrl(subTrs.get(0)));
					if(roundObject == null){
						continue;
					}
					break;
				}catch(Exception e){
					logger.info(e);
					logger.info("请求往返数据第：" + (i + 1) + "次失败");
					switchProxyipByHttClient();
				}
			}
			
			if(roundObject == null){
				throw new Exception("抓取往返数据失败");
			}
			
			Document doc = Jsoup.parse(roundObject);
			//返程航线
			Elements returnTrs = doc.getElementById("revenueSegments").select("tr[id$=trSegBlock]");
			parseRoundReturn(entity,cabin,returnTrs,cabinElement);
		}
	}
	
	/**
	 * 组织往返回程
	 * @param entity 航班实体
	 * @param cabin 仓位实体
	 * @param trs
	 * @throws Exception 
	 */
	private void parseRoundReturn(DoublePlaneInfoEntity entity,CabinEntity cabin,Elements trs,Element cabinElement) throws Exception{
		logger.info("解析返程---------");
		ReturnDoublePlaneInfoEntity returnEntity = null;
		for(Element tr : trs){
			//每一个航班里面有若干个tr  单数tr是航班，双数是中转信息
			Elements allTrs = tr.select("td.tdSegmentBlock table tbody>tr");
			Elements subTrs = getSubTranTrs(allTrs);
			String flightNos = "";
			Elements flighttds = tr.select("td.tdSegmentDtl");
			//用各段的航班号拼装起来，唯一确定一条航线
			for(Element flighttd : flighttds){ 
				String flightNo= flighttd.select("div").first().select("b").text();
				flightNos += flightNo;
			}
			
			returnEntity = getExistReturnEntity(entity, flightNos);
			//不存在这段回程，新添加回程航班
			if(returnEntity == null){
				Element trfirst= subTrs.first();
				Element trlast = subTrs.last();
				returnEntity = (ReturnDoublePlaneInfoEntity)PlaneInfoEntityBuilder.buildPlaneInfo(taskQueue, carrierKey, carrierName, carrierFullName,getStartTime(trfirst) , getEndTime(trlast),
						getFlightNo(trfirst), null, null, null, getFlightType(trfirst),ReturnDoublePlaneInfoEntity.class);
				returnEntity.setFlightDuration(getStayTime(getFlightDuration(trlast)));
				//回程中转
				if(subTrs.size() > 1){
					for(int i = 0;i < subTrs.size(); i = i + 2){
						String no = getFlightNo(subTrs.get(i));
						String key = no.substring(0,2);
						ReturnTransitEntity trans = PlaneInfoEntityBuilder.buildReturnTransitEntity(no, no,
								key, getCarriName(key), getCarriFullName(key), getFromAirPort(subTrs.get(i)), getFromAirPortName(subTrs.get(i)),
								getToAirPort(subTrs.get(i)), getToAirPortName(subTrs.get(i)), getFlightType(subTrs.get(i)));
						//这个字段记不了，因为有多种舱位类型，而一个航班的中转是唯一的
						//trans.setCabinName();
 						trans.setStartTime(getFormat(getStartTime(subTrs.get(i))));
						trans.setEndTime(getFormat(getEndTime(subTrs.get(i))));
						//中转的停留时间记在前一中转中
						if(i < subTrs.size() - 1){
							trans.setStayTime(getStopStayTime(subTrs.get(i + 1)));
						}
						returnEntity.getReturnTransits().add(trans);
					}
				}
				entity.getReturnPlaneInfos().add(returnEntity);
			}
			
			addStopOver(entity, getSubStopTrs(allTrs));
			String cabinName = getCabinName(subTrs.get(0));
			ReturnCabinEntity returnCabin = PlaneInfoEntityBuilder.buildCabinInfo(cabinElement.text(),RegHtmlUtil.regStr(cabinName, "\\((\\w{1})\\)") ,cabinName, 
					null, null, null, null, null, ReturnCabinEntity.class);
			returnEntity.getReturnCabins().add(returnCabin);
			
			
			
			//来回程都是一个价的,添加来回程关系 2层页面只有合计价
			CabinRelationEntity relation = new CabinRelationEntity();
			relation.setCabinId(cabin.getId());
			relation.setReturnCabinId(returnCabin.getId());
			String priceText = tr.select("td.tdPrice").select("span.fResultsPrice").first().text().replaceAll(",", "");
			relation.setTotalFullPrice(Double.valueOf(priceText.replaceAll("[^\\d\\.]", "")));
			
			String currency = priceText.replaceAll("[\\d]", "");
			currency = currency.replaceAll("\\$", "USD").replaceAll("￥", "CNY").replaceAll("[^A-Z]", "");
			if(!currency.equals("CNY") && !currency.equals("USD")){
				logger.info("价格符号：" + currency + "请查看");
				throw new Exception("价格符号错误");
			}
			entity.setCurrency(currency);
			
			//请求税费和裸价的
			for(int i = 0;i < queryRoundTaxTimes;i++){
				logger.info("返程抓取税费开始----------");
				try{
					String page = fetchPrice(getPriceUrl(subTrs.first()));
					Document dc = Jsoup.parse(page);
					relation.setFullPrice(getDouble(dc.getElementById("ctl00_ContentInfo_priceRevenueSummary_Price_ctl00_tdDisplayValue").text()));
					relation.setTaxesPrice(getDouble(dc.getElementById("ctl00_ContentInfo_priceRevenueSummary_Price_ctl01_tdDisplayValue").text()));
					relation.setTotalFullPrice(getDouble(dc.getElementById("ctl00_ContentInfo_priceRevenueSummary_Price_ctl02_tdDisplayValue").text()));
					break;
				}catch(Exception e){
					logger.info("往返第" + (i + 1) + "次请求裸价和税费失败", e);
					switchProxyipByHttClient();
				}
			}
			
			entity.getCabinRelations().add(relation);
		}
	}
	
	/**
	 * 增加经停信息
	 * @param entity
	 * @param flghtNo
	 */
	private void addStopOver(AbstractPlaneInfoEntity entity,Elements subStr){
		try{
			String flightNo = null;
			for(int i = 0;i < subStr.size() - 1;i++){
				if(!subStr.get(i).select("td").hasClass("tdStopMsg")){
					flightNo = getFlightNo(subStr.get(i));
				}else{
					addStop(entity,flightNo,subStr.get(i));
				}
			}
		}catch(Exception e){
			logger.info("增加经停信息失败", e);
		}
	}

	private void addStop(AbstractPlaneInfoEntity entity,String flightNo,Element tr){
		if(entity instanceof SinglePlaneInfoEntity){
			StopOverEntity stopOver = new StopOverEntity();
			stopOver.setStayTime(getStopStayTime(tr));
			stopOver.setStopCity(getStopCity(tr));
			stopOver.setFlightNo(flightNo);
			((SinglePlaneInfoEntity)entity).getStopOvers().add(stopOver);
		}else if(entity instanceof DoublePlaneInfoEntity){
			StopOverEntity stopOver = new StopOverEntity();
			stopOver.setStayTime(getStopStayTime(tr));
			stopOver.setStopCity(getStopCity(tr));
			stopOver.setFlightNo(flightNo);
			((DoublePlaneInfoEntity)entity).getStopOvers().add(stopOver);
		}else if(entity instanceof ReturnDoublePlaneInfoEntity){
			ReturnStopOverEntity stopOver = new ReturnStopOverEntity();
			stopOver.setStayTime(getStopStayTime(tr));
			stopOver.setStopCity(getStopCity(tr));
			stopOver.setFlightNo(flightNo);
			((ReturnDoublePlaneInfoEntity)entity).getReturnStopOvers().add(stopOver);
		}
	}
	
	private static Double getDouble(String text){
		return Double.valueOf(text.replaceAll("[^\\d\\.]",""));
	}
	
	/**
	 * 排除不是航班和不是中转信息的其他信息
	 * @param allTrs
	 * @return
	 */
	private static Elements getSubTranTrs(Elements allTrs){
		Elements subTrs = new Elements();
		for(Element e : allTrs){
			if(!e.select("td.tdDepart").isEmpty() || (!e.select("td.tdStopMsg").isEmpty() && !e.select("td.tdStopMsg").text().matches(".*停止.*"))){
				subTrs.add(e);
			}
		}
		return subTrs;
	}
	
	/**
	 * 排除不是航班和不是经停信息的其他信息
	 * @param allTrs
	 * @return
	 */
	private static Elements getSubStopTrs(Elements allTrs){
		Elements subTrs = new Elements();
		for(Element e : allTrs){
			if(!e.select("td.tdDepart").isEmpty() || (!e.select("td.tdStopMsg").isEmpty() && e.select("td.tdStopMsg").text().matches(".*停止.*"))){
				subTrs.add(e);
			}
		}
		return subTrs;
	}
	
	private static String getStopCity(Element tr){
		return RegHtmlUtil.regStr(tr.select("td").text(),"在(\\W*)的");
	}
	
	/**
	 * 查看某个去程对用的回程是否已经存在
	 * @param entity
	 * @param flightNos
	 * @return
	 */
	private ReturnDoublePlaneInfoEntity getExistReturnEntity(DoublePlaneInfoEntity entity,String flightNos){
		ReturnDoublePlaneInfoEntity returnEntity = null;
		Set<ReturnDoublePlaneInfoEntity> returnPlaneInfos = entity.getReturnPlaneInfos();
		if(returnPlaneInfos != null && !returnPlaneInfos.isEmpty()){
			for(ReturnDoublePlaneInfoEntity e : returnPlaneInfos){
				String nos = "";
				if(e.getReturnTransits() == null || e.getReturnTransits().isEmpty()){
					nos = e.getFlightNo();
				}else{
					for(ReturnTransitEntity t : e.getReturnTransits()){
						nos += t.getFlightNo();
					}
				}
				if(flightNos.equals(nos)){
					returnEntity = e;
					break;
				}
			}
		}
		return returnEntity;
	}
	
	/**
	 * 抓取返程信息
	 * @param strUrl
	 * @return
	 * @throws Exception
	 */
	private String fetchRound(String strUrl) throws Exception{
		HttpClient h = getHttpClient();
		//因为源url地址有特殊符号，所以用URL封装一下
		URL url = new URL(strUrl);
		URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), url.getQuery(), null);
		HttpGet g = new HttpGet(uri); 
		g.addHeader("Referer",SEARCHURL);
		//页面有重定向的，但是重定向的地址也有特殊符号
	/*	h.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, false);  
		HttpGet g = new HttpGet(uri); 
		HttpResponse res = h.execute(g);
		EntityUtils.toString(res.getEntity());
		String redirect = res.getLastHeader("Location").getValue();
		url = new URL(redirect.startsWith("http") ? redirect :("http://www.united.com" + redirect));
		uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), url.getQuery(), null);
	    g = new HttpGet(uri);
		res = h.execute(g);
		h.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, true);  */
		return excuteRequest(h, g, true);
	}
	
	/**
	 * 抓取税费等信息
	 * @param strUrl
	 * @return
	 * @throws Exception
	 */
	private String fetchPrice(String strUrl) throws Exception{
		HttpClient h = getHttpClient();
		//因为源url地址有特殊符号，所以用URL封装一下
		URL url = new URL(strUrl);
		URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), url.getQuery(), null);
		//页面有重定向的，但是重定向的地址也有特殊符号
		//h.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, false);  
		HttpGet g = new HttpGet(uri); 
	/*	EntityUtils.toString(res.getEntity());
		String redirect = res.getLastHeader("Location").getValue();
		url = new URL("http://www.united.com" + redirect);
		uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), url.getQuery(), null);
	    g = new HttpGet(uri);
		res = h.execute(g);*/
		//h.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, true);  
		return excuteRequest(h, g, true);
	}
	
	
	/**
	 * 转换yyyy-MM-dd HH:mm的数据
	 * @param date
	 * @return
	 * @throws ParseException
	 */
	private static Date getFormat(String date) throws ParseException{
		return format.parse(date);
	}
	
	/**
	 * 请求返程地址
	 * @param tr
	 * @return
	 */
	private static String getRoundUrl(Element tr){
		String onclick = tr.select("td.tdPrice>div.divSelect input").get(0).attr("onclick");
		return SEARCH2URL + "?" + RegHtmlUtil.regStr(onclick, "../../../../.*?searchResult.*?\\?(.*?)\"").replaceAll("SID=.*?&","").replaceAll("fp=.*?&", "");
	}
	
	/**
	 * 请求税费地址
	 * @param tr
	 * @return
	 */
	private static String getPriceUrl(Element tr){
		String onclick = tr.select("td.tdPrice>div.divSelect input").get(0).attr("onclick");
		return "https://www.united.com/web/zh-CN/apps/booking/flight/reviewRevenue.aspx" + "?" + RegHtmlUtil.regStr(onclick, "../../../../.*?searchResult.*?\\?(.*?)\"");
	}
	
	/**
	 * 获取舱位名称
	 * @param tr
	 * @return
	 */
	private static String getCabinName(Element tr){
		try{
			return tr.select("td.tdSegmentDtl span[id$=Span1] b").text();
		}catch(Exception e){
			return null;
		}
	}
	
	/**
	 * 获取总时长
	 * @param tr
	 * @return
	 */
	private static String getFlightDuration(Element tr){
		Elements spans = tr.select("td.tdTrvlTime").first().select("span.PHead");
		if(spans != null && !spans.isEmpty()){
			return spans.first().select("b").text();
		}
		return null;
	}
	
	/**
	 * XX小时XX分钟转换成毫秒
	 * @param time
	 * @return
	 */
	private static Long getStayTime(String time){
		if(time == null){
			return null;
		}
		String hourStr = RegHtmlUtil.regStr(time,"(\\d*)\\D*?小时");
		String minuteStr = RegHtmlUtil.regStr(time,"(\\d*)\\D*?分钟");
		int hour = hourStr == null ? 0 : Integer.valueOf(hourStr);
		int minute = minuteStr == null ? 0 : Integer.valueOf(minuteStr);
		return (hour * 60 + minute) * 60 * 1000l;
	}
	
	/**
	 * 获取中转和经停停留时间 
	 * @param tr
	 * @return
	 */
	private static Long getStopStayTime(Element tr){
		String text = tr.select("td").text();
		return getStayTime(RegHtmlUtil.regStr(text, "为(.*\\d+.*)"));
	}
	
	private static String getFromAirPort(Element tr){
		String port = tr.select("td.tdDepart>div").get(3).text();
		return RegHtmlUtil.regStr(port, "\\(([A-Z]{3})");
	}
	
	private static String getFromAirPortName(Element tr){
		String port = tr.select("td.tdDepart>div").get(3).text();
		return port.replaceAll("\\(.*?\\)", "");
	}
	
	private static String getToAirPort(Element tr){
		String port = tr.select("td.tdArrive>div").get(3).text();
		return RegHtmlUtil.regStr(port, "\\(([A-Z]{3})");
	}
	
	private static String getToAirPortName(Element tr){
		String port = tr.select("td.tdArrive>div").get(3).text();
		return port.replaceAll("\\(.*?\\)", "");
	}
	
	/**
	 * 航班号
	 * @param tr
	 * @return
	 */
	private static String getFlightNo(Element tr){
		Elements divs = tr.select("td.tdSegmentDtl>div");
		return divs.first().select("b").first().text();
	}
	
	/**
	 * 航班类型
	 * @param tr
	 * @return
	 */
	private static String getFlightType(Element tr){
		Elements divs = tr.select("td.tdSegmentDtl>div");
		return divs.get(2).select("b").first().text();
	}
	
	/**
	 * 根据行信息获得开始时间
	 * @param tr
	 * @return
	 */
	private static String getStartTime(Element tr){
		Elements departDivs = tr.select("td.tdDepart>div");
		return getFormatTime(departDivs.get(2).text(), departDivs.get(1).select("strong").get(0).text());
	}
	
	/**
	 * 根据行信息获取结束时间
	 * @param tr
	 * @return
	 */
	private static String getEndTime(Element tr){
		Elements departDivs = tr.select("td.tdArrive>div");
		return getFormatTime(departDivs.get(2).text(), departDivs.get(1).select("strong").get(0).text());
		
	}
	
	
	/**
	 *统一日期格式 转换成 yyyy-MM-dd HH:mm
	 * @param date（2014年8月1日 (星期五)）
	 * @param time（5:30 p.m.）
	 * @return
	 */
	private static String getFormatTime(String date,String time){
		StringBuilder sb = new StringBuilder();
		date = date.replaceAll("[年月]", "-").replaceAll("[^\\d\\-]", "");
		String[] arr = date.split("-");
		sb.append(arr[0]);
		sb.append("-");
		sb.append(arr[1].length() == 1 ? ("0" + arr[1]) : arr[1]);
		sb.append("-");
		sb.append(arr[1].length() == 1 ? ("0" + arr[2]) : arr[2]);
		sb.append(" ");
		arr = time.split(":");
		String hour = arr[0];
		String minute = arr[1];
		if(time.indexOf("p.m") >= 0){
			hour = String.valueOf(Integer.valueOf(hour) + 12);
		}
		if(hour.length() == 1){
			hour = "0" + hour;
		}
		if(minute.length() == 1){
			minute = "0" + minute;
		}
		sb.append(hour).append(":").append(minute);
		return sb.toString();
	}
	
	/**
	 * 把日期处理成请求需要的格式，yyyy-MM-dd 转换成MM/dd/yyyy
	 * 例 2014-08-12转成 8/12/2014
	 * @param date
	 * @return
	 */
	private static String getFormatDate(String date){
		String[] arr = date.split("-");
		StringBuilder sb = new StringBuilder();
		sb.append(arr[1].replaceAll("^0", ""));
		sb.append("/");
		sb.append(arr[2].replaceAll("^0", ""));
		sb.append("/");
		sb.append(arr[0]);
		return sb.toString();
	}
	
	/**
	 * test
	 * @return
	 * @throws Exception
	 */
	private Map<String,String> getParams() throws Exception{
		Map<String,String> params = new HashMap<String, String>();
		BufferedReader reader = new BufferedReader(new FileReader(new File("C:/Users/like/Desktop/test.txt")));
		String s;
		while((s = reader.readLine()) != null){
			String[] arr = s.split("=", 2);
			params.put(arr[0], arr[1]);
		}
		reader.close();
		return params;
	}
	
	@Override
	public boolean validateFetch(Object fetchObject) throws Exception {
		if(fetchObject == null){
			return false;
		}
		return true;
	}
	
	  public static void main(String[] args) throws Exception {
	        TaskModel taskModel = new TaskModel();
	        taskModel.setFromCity("PEK"); 
	        taskModel.setFromCityName("北京");
	        taskModel.setToCity("BOS");
	        taskModel.setToCityName("洛杉矶");
	        taskModel.setFlightDate("2015-01-12");
	        taskModel.setIsReturn(1);
	        taskModel.setIsInternational(1);
	        taskModel.setReturnGrabDate("2015-03-12");
	        
	        UnitedAdapter adapter = new UnitedAdapter(taskModel);
	        Object obj = adapter.fetch(null);
	        List<Object> list = adapter.paraseToVo(obj);
	        adapter.printJson( list, "d:/ua.txt");
	    }
}
